![]() |
Swift Stories |
View in web browser |
Featured work: Marcel
#2 - Jan 23, 2025 The power of extensibility in Swift appsWelcome to issue 2!The software we build serves a diverse world with varying needs across people and organizations. Creating solutions that cater to everyone's requirements can introduce complexity into our products. This is where extensibility comes in – making common tasks straightforward while keeping everything else possible. To tackle this challenge, we first need to identify what's core to our app's domain and where extensibility points lie. Take GitHub Actions as an example: while build environments and standard automation formats are core elements, individual steps can be extended through first and third-party code. Similarly, in the Swift ecosystem, SPM handles package graph definition and interpretation at its core, while allowing developers to share and extend functionality through build-tool plugins. Consider how the Swift compiler works within Xcode's build system – it freezes your app's static shape into a binary. While content might change, the app's capabilities reflect what's written in code or defined in a SwiftUI tree. But what if we could tell the compiler to resolve certain aspects at runtime? While not the default approach, it's entirely feasible. The simplest form of extensibility is declarative. You define and parse a schema, then use it to adjust the app. This could be anything from themes (defined by you, users, or a community) to dropdown menu actions or UI directives – similar to backend-driven UI approaches some companies employ. For instance, Alexander Weiß created swiftui-theming, enabling not just predefined theme selection but potentially supporting a community-driven theme ecosystem. As needs evolve, you might want to offer more advanced customization options, similar to Raycast or VSCode extensions. This might include letting developers customize your app's business logic. The first step is identifying extension points – what exactly are people extending? Your business logic may need adaptation to interface with external code components. The nature of this contract depends on your app's specific needs. Swift build-tool plugins demonstrate this by running at specific points during compilation, such as executing SwiftLint checks. Technology choice comes next. The simplest approach uses spawned executables for communication – this is how Swift Macros work under the hood. While functional, debugging can be challenging. Raycast took an innovative approach, detailed in their blog post, by adopting NodeJS as their extension runtime. This gives developers access to the vast NPM package ecosystem, though it requires careful consideration of security through their review process. For those seeking alternatives that leverage Swift, WebAssembly (WASM) and specifically SwiftWasm offer promising solutions. The PointFree team has explored this for frontend development, and discussions are ongoing about its potential use in Swift Macros. WASM's built-in security model provides natural boundaries for extension capabilities while maintaining the flexibility developers need. Extensibility in Swift apps remains an exciting frontier with tremendous potential for customization and adaptation. We're eager to see more apps like Raycast drawing inspiration from web ecosystems while embracing native development. Imagine more applications like Obsidian, VSCode, or Slack – but built natively, supported by rich plugin ecosystems that enhance our daily experience. Tools & sites
Worthy Five: Natan RolnikNatan Rolnik is an Apple platforms developer at Monday.com, where he works on the iOS and macOS apps. He is also the author of the Swift Toolkit – a blog and a podcast about using Swift to craft developer tools.
Food for thought
|